/**  
* Copyright (c) 2008, Noel Lynch All rights reserved. Redistribution and use  
* in source and binary forms, with or without modification, are permitted  
* provided that the following conditions are met: Redistributions of source  
* code must retain the above copyright notice, this list of conditions and the  
* following disclaimer. Redistributions in binary form must reproduce the above  
* copyright notice, this list of conditions and the following disclaimer in the  
* documentation and/or other materials provided with the distribution. Neither  
* the name of Noel Lynch nor the names of contributors may be used to  
* endorse or promote products derived from this software without specific prior  
* written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A  
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
*/
// Sep 4, 2008

package com.sceneworker.util.swing.timelineeditor;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

public class KeyFramesPanel extends KeyFrameTimeLanePanelComponent implements MouseListener, MouseMotionListener {

	static		final	private		Dimension	kMaxDim = new Dimension(800, 60);
	
	private		ArrayList<Float>	mcla_keyFrames;
	private		Float				mcl_selectedKeyFrame = null;
	private		float				mf_curTimeSel = -1;
	
	private		KeyFramePanelEventListener		mcl_listener;
	
	public KeyFramesPanel(KeyFrameTimeLinePanel cl_parent) {
		super(cl_parent);
		
		mcla_keyFrames = new ArrayList<Float>();
		
		addMouseListener(this);
		addMouseMotionListener(this);
	}
	
	public	void	setKeyFramePanelListener(KeyFramePanelEventListener cl_l) {
		mcl_listener = cl_l;
	}
	
	public	KeyFramePanelEventListener		getKeyFramePanelListener() {
		return mcl_listener;
	}
	
	public	void	setCurTimeSel(float f_v) { mf_curTimeSel = f_v; }
	
	public	float	getCurTimeSel() { return mf_curTimeSel; }
	
	public	Float	getSelectedKeyFrame() {
		return mcl_selectedKeyFrame;
	}
	
	public	void	addKeyFrame(float f_v) {
		mcla_keyFrames.add(new Float(f_v));
	}
	
	public	void	removeKeyFrameAtTime(float f_t) {
		for(Float lcl_t : mcla_keyFrames) {
			if(f_t == lcl_t.floatValue()) {
				mcla_keyFrames.remove(lcl_t);
				return;
			}
		}
	}
	
	@Override
	public Dimension getMaximumSize() {
		Dimension		lcl_dim = super.getMaximumSize();
		return new Dimension(lcl_dim.width, 30);
	}

	@Override
	public Dimension getMinimumSize() {
		Dimension		lcl_dim = super.getMinimumSize();
		return new Dimension(lcl_dim.width, 30);
	}

	@Override
	public Dimension getPreferredSize() {
		Dimension		lcl_dim = super.getPreferredSize();
		return new Dimension(lcl_dim.width, 30);
	}


	@Override
	protected	void	paintComponent(Graphics cl_g) {
		Graphics2D		lcl_g = (Graphics2D)cl_g.create();
	
		drawBackgroud(lcl_g);
		drawMarkers(lcl_g);
		
		drawKeyFrames(lcl_g);
		
		lcl_g.dispose();
	}
	
	private	void	drawKeyFrames(Graphics2D cl_g) {
		int		li_pxPerSecond = mcl_parent.getPixelsPerSecond();
		int		li_start = mcl_parent.getStartTimeOfBar();
		int		li_t, li_x;
		float	lf_t;
		
		for(Float lcl_t : mcla_keyFrames) {
			lf_t = lcl_t.floatValue();
			lf_t -= li_start;
			li_t = (int)lf_t;
			
			li_x = li_t * li_pxPerSecond;
			li_x += ((float)li_pxPerSecond * (lf_t - li_t));
			
			if(lcl_t == mcl_selectedKeyFrame) {
				cl_g.setColor(Color.red);
				cl_g.fillOval(li_x - 3, (getHeight() >> 1) - 3, 6, 6);
			} else {
				cl_g.setColor(Color.green);
				cl_g.fillOval(li_x - 3, (getHeight() >> 1) - 3, 6, 6);
			}
			
			cl_g.setColor(Color.black);
			cl_g.drawOval(li_x - 3, (getHeight() >> 1) - 3, 6, 6);
			
		}
	}
	
		
	private	void	drawBackgroud(Graphics2D cl_g) {
		cl_g.setColor(new Color(230, 230, 230));
		cl_g.fillRect(0, 0, getWidth(), getHeight());
	}
	
	private	void	drawMarkers(Graphics2D cl_g) {
		int		li_pxPerSecond = mcl_parent.getPixelsPerSecond();
		int		li_pxPerMiliSecond = li_pxPerSecond / 10;
		
		int		li_start = mcl_parent.getStartTimeOfBar();
		int		li_end = mcl_parent.getEndTimeOfBar();
		
		int		li_x = 0;
		int		li_x2;
		
		for(int li_index = li_start; li_index < li_end; li_index++) {
			li_x = li_pxPerSecond * (li_index - li_start);		// find offset to start at
			li_x2 = li_x + (li_pxPerSecond >> 1);
			
			cl_g.setColor(Color.blue);
			cl_g.drawLine(li_x, 0, li_x, getHeight());
			
			cl_g.setColor(new Color(0, 219, 255));
			cl_g.drawLine(li_x2, 0, li_x2, getHeight());
			
			cl_g.setColor(new Color(184, 219, 255));
			
			for(int li_temp = li_x + li_pxPerMiliSecond; li_temp < li_x2; li_temp += li_pxPerMiliSecond) {
				cl_g.drawLine(li_temp, 0, li_temp, getHeight());
			}
			
			for(int li_temp = li_x2 + li_pxPerMiliSecond; li_temp < (li_x + li_pxPerSecond); li_temp += li_pxPerMiliSecond) {
				cl_g.drawLine(li_temp, 0, li_temp, getHeight());
			}
		}
		
		li_x = (int)((mf_curTimeSel - li_start) * (float)li_pxPerSecond);
		cl_g.setColor(Color.red);
		cl_g.drawLine(li_x, 0, li_x, getHeight());
	}

	public void mouseClicked(MouseEvent cl_e) {
		
		int		li_pxPerSecond = mcl_parent.getPixelsPerSecond();
		int		li_start = mcl_parent.getStartTimeOfBar();
		int		li_t;
		float	lf_t;
		
		Rectangle	lcl_r = new Rectangle();
		lcl_r.y = (getHeight() >> 1) - 3;
		lcl_r.width = lcl_r.height = 6;
		
		mf_curTimeSel = li_start + ((float)cl_e.getPoint().x / (float)li_pxPerSecond);
		
		for(Float lcl_t : mcla_keyFrames) {
			lf_t = lcl_t.floatValue();
			lf_t -= li_start;
			li_t = (int)lf_t;
			
			lcl_r.x = li_t * li_pxPerSecond;
			lcl_r.x += ((float)li_pxPerSecond * (lf_t - li_t));

			if(lcl_r.contains(cl_e.getPoint())) {
				if(mcl_selectedKeyFrame != lcl_t) {
					mcl_selectedKeyFrame = lcl_t;
					
					if(mcl_listener != null) {
						mcl_listener.newKeyFrameSelection(this);
					}
				}
				
				repaint();
				
				return;
			}
		}
		
		
		mcl_selectedKeyFrame = null;
		
		if(mcl_listener != null) {
			mcl_listener.newTimeSelection(this);
		}
		
		repaint();
	}

	public void mouseEntered(MouseEvent arg0) {
	}

	public void mouseExited(MouseEvent arg0) {
	}

	public void mousePressed(MouseEvent cl_e) {
		if(cl_e.isPopupTrigger()) {
			KeyFramesPopMenu		lcl_menu = new KeyFramesPopMenu(this);
			
			lcl_menu.show(this, cl_e.getPoint().x, cl_e.getPoint().y);
			return;
		}
	}

	public void mouseReleased(MouseEvent cl_e) {
		if(cl_e.isPopupTrigger()) {
			KeyFramesPopMenu		lcl_menu = new KeyFramesPopMenu(this);
			
			lcl_menu.show(this, cl_e.getPoint().x, cl_e.getPoint().y);
			return;
		}
	}
	
	public	interface	KeyFramePanelEventListener {
		void	makeNewKeyFrame(KeyFramesPanel cl_panel);
		void	makeNewKeyFrame(float f_time);
		void	deleteKeyFrame(KeyFramesPanel cl_panel);
		void	newKeyFrameSelection(KeyFramesPanel cl_panel);
		void	newTimeSelection(KeyFramesPanel cl_panel);
		void	copyKeyFrame(KeyFramesPanel cl_panel);
		void	cutKeyFrame(KeyFramesPanel cl_panel);
		void	pasteKeyFrame(KeyFramesPanel cl_panel);
		boolean	isKeyFrameInBuffer(KeyFramesPanel cl_panel);
	}

	public void mouseDragged(MouseEvent e) {
	}

	public void mouseMoved(MouseEvent cl_e) {
		int		li_pxPerSecond = mcl_parent.getPixelsPerSecond();
		int		li_start = mcl_parent.getStartTimeOfBar();
		
		setToolTipText("time = " + (li_start + ((float)cl_e.getPoint().x / (float)li_pxPerSecond)));
	}
	
}
